#ifndef SHIPMANAGE_H
#define SHIPMANAGE_H

#pragma once

/* **********************************************************************************************
 *
 * 船舶数据管理抽象基类。派生的子类在一个程序中只能实例化一个。
 * innerShip就是fleetShip，有时可能会是teamShip
 *
 * ******************************************************************************************** */

#include <QObject>
#include "ModelShip.h"
#include <QSharedPointer>
#include <QElapsedTimer>
#include <QThread>
#include <QMap>
#include "model/definecoor.h"

namespace ns_yht
{

#define SHIPMANAGE ShipManage::instance()

    class ShipManage : public QObject
    {
        Q_OBJECT

    public:
        ShipManage();
        ~ShipManage();

        static ShipManage *instance();

        virtual void startThread(QThread &thread);

        // void getThreadStatus();

        const QMap<quint64, QSharedPointer<ModelShip>> &getShipList() const;
        // const QVector<quint64> &getMyShipList(int id = 0) const;
        QSharedPointer<ModelShip> getOwnShip() const;
        QSharedPointer<ModelShip> getSearchedShip() const;
        const QVector<QPair<quint64, QString>> &getSearchedResult() const;
        // const QVector<QSharedPointer<ModelShip>> &getDangerousShipList() const;

        const CoordinatesCollection &getAlertArea() const;

        bool ownValid() const;
        int getAisShipCount() const;
        int getArpaShipCount() const;
        int getShipCount(int &aisCount, int &arpaCount) const;
        double getRadius_nm() const;

        void setShowInner(bool ishow = true);
        void setShowOuter(bool ishow = true);
        bool showInner() const;
        bool showOuter() const;

        // ShipDisplayMode getDisplayMode() const;

        // 一般不需要外部调用。当外部需要立即重新刷新时调用，比如昼夜模式变了，需要重建绿点图层
        virtual void request() = 0;

        int getPanelId() const;
        virtual bool isBusy() const;

        void latlonAdjust(QSharedPointer<ModelShip> ship, int type);

        const double getDepth() const;
        const double getDraught() const;
        const int getPosState() const;

        struct SimpleShipInfo
        {
            double dcpa{0};
            double tcpa{0};
            QString name;
            bool emergency{true};
            bool ensured{false};
            qint64 time{0};

            SimpleShipInfo() = default;
            SimpleShipInfo(double d, double t, const QString &sname, bool e, qint64 tm)
            {
                dcpa = d;
                tcpa = t;
                name = sname;
                emergency = e;
                time = tm;
            }
        };

        const QMap<quint64, SimpleShipInfo> &getShipCollisionMap() const;

    public slots:
        virtual void searchOneShip(quint64 mmsi, int panelId = 0) = 0;
        virtual void searchShipWithKeyword(const QString &keyword, int panelId = 0) = 0;
        virtual void searchTrack(quint64 mmsi, const QString &startTime, const QString &endTime) = 0;

        virtual void onEhhMapChanged();

        // virtual void onRadiusChanged(int radius_nm);
        void onSetOwnshipCoordinate(double lat, double lon);
        void onOwnshipMmsiChanged(quint64 mmsi);

        virtual void onRadiusChanged(double radius_nm);

        // virtual void onStartTimer();
        // virtual void onNeedUpdate();
        void ensure(quint64 mmsi, bool isEnsured = true);

    signals:
        void ownShipChanged(bool repaint = false); // 正常情况下只需要重新计算和本船相关的信息，图形会在接下来的shipsChanged中刷新;但手动定位船舶时不仅更新本船信息，也需要刷新图形
        void shipsChanged();
        void innerShipsChanged();
        void searchOneShipFinished();
        void searchShipsWithKeywordFinished();
        void searchTrackFinished();
        void shipCollisionAlarm(quint64 mmsi, double tcpa, QString name, bool emergency = true);
        void cancelShipCollision(quint64 mmsi, bool emergency = true);
        void cancelAllShipCollision();
        void requestFleet();
        void waterDepthChanged(double depth, double offset);
        void alertUsermap();
        void cancelUsermap();
        // void dangerousShipListChanged();

        // void needUpdateGraph(const QVariant &listFeature);

        void posStateChange(int state);

        void autoShipCollision(quint64 mmsi, bool isEnsure);

    protected:
        // void timerEvent(QTimerEvent *event) override;
        // QString getShipIcon(ModelShip *ship);
        /*
         * 外部船舶、内部船舶、本船，构成所有船舶，不重复
         * 这样在标绘船舶时不需要对每个船舶判断
         */
        QMap<quint64, QSharedPointer<ModelShip>> m_shipList;
        QSharedPointer<ModelShip> m_ownShip;
        // 当前搜索（选中）船舶，为null或者指船舶列表中的一艘，没在列表中则new一个再放入船舶列表
        QSharedPointer<ModelShip> m_searchedShip;
        QVector<QPair<quint64, QString>> m_searchedResult;
        // QVector<QSharedPointer<ModelShip>> m_dangerousShipList;

        QMap<quint64, SimpleShipInfo> m_shipCollisionMap;

        quint64 getMaxTcpaShipFromCollisionMap(double &tcpa) const;

        bool m_showOuter{true};
        bool m_showInner{true};
        int m_width{1920};
        int m_height{1024};

        qreal m_minLat;
        qreal m_maxLat;
        qreal m_minLon;
        qreal m_maxLon;
        double m_radius_nm{3}; // 需要显示的船舶半径，NM
        double m_radius{5556}; // 需要显示的船舶半径，米
        int m_aisCount{0};     // 设定半径内AIS船舶数量
        int m_arpaCount{0};    // 设定半径内ARPA船舶数量
        int m_fusedCount{0};   // 设定半径内融合船舶数量

        static ShipManage *g_shipManage; // 指向一个子类实例

        // int m_timerId{0};
        QElapsedTimer m_elapsedTimer;
        bool m_startCount{false};
        int m_panelId{0}; // 多个窗体对船舶搜索，返回的结果只在对应的窗口显示

        int m_posState{-1};
        double m_depth{0.0};   // 水深
        double m_draught{0.0}; // 吃水

        CoordinatesCollection m_alertAreas; // 警戒区
    };

} // namespace ns_yht

#endif
